package org.fast.develop.logicflow.runtime.expression;

/**
 * 项 目 名：gs-tto-data-mapping
 * 源文件名：com.geekstorm.tto.datamapping.core.expression.ExpressionManager
 * 文件版本：1.0.0
 * 创建人： 莫寅
 * 创建日期：2020-07-23 11:41
 * 修改作者：莫寅
 * 修改日期：2020-07-23 11:41
 * 文件描述：
 * By：2020 © CompanyName  , Inc. All Rights Reserved.
 */

import de.odysseus.el.ExpressionFactoryImpl;
import de.odysseus.el.util.SimpleContext;
import org.fast.develop.logicflow.runtime.expression.el.GsElContext;
import org.fast.develop.logicflow.runtime.expression.el.ReadOnlyMapELResolver;

import javax.el.*;
import java.util.Map;

/**
 * <p>
 * Central manager for all expressions.
 * </p>
 * <p>
 * Process parsers will use this to build expression objects that are stored in the
 * process definitions.
 * </p>
 * <p>
 * Then also this class is used as an entry point for org.fast.develop.logicflow.runtime evaluation of the
 * expressions.
 * </p>
 *
 * @author Tom Baeyens
 * @author Dave Syer
 * @author Frederik Heremans
 */
public class ExpressionManager {

	protected ExpressionFactory expressionFactory;

	// Default implementation (does nothing)
	protected ELContext parsingElContext = createParsingElContext();

	protected Map<Object, Object> beans;

	public ExpressionManager() {
		this(null);
	}

	public ExpressionManager(boolean initFactory) {
		this(null, false);
	}

	public ExpressionManager(Map<Object, Object> beans) {
		this(beans, true);
	}

	public ExpressionManager(Map<Object, Object> beans, boolean initFactory) {
		// Use the ExpressionFactoryImpl in activiti build in version of juel,
		// with parametrised method expressions enabled
		expressionFactory = new ExpressionFactoryImpl();
		this.beans = beans;
	}

	public Expression createExpression(String expression) {
		ValueExpression valueExpression = expressionFactory.createValueExpression(parsingElContext, expression.trim(),
				Object.class);
		return new JuelExpression(valueExpression, expression, this);
	}

	public void setExpressionFactory(ExpressionFactory expressionFactory) {
		this.expressionFactory = expressionFactory;
	}

	public ELContext getElContext(VariableScope variableScope) {
		ELContext elContext = null;

		if (elContext == null) {
			elContext = createElContext(variableScope);
		}

		return elContext;
	}

	protected GsElContext createElContext(VariableScope variableScope) {
		ELResolver elResolver = createElResolver(variableScope);
		return new GsElContext(elResolver);
	}

	protected ELResolver createElResolver(VariableScope variableScope) {
		CompositeELResolver elResolver = new CompositeELResolver();
		elResolver.add(new VariableScopeElResolver(variableScope));

		if (beans != null) {
			// ACT-1102: Also expose all beans in configuration when using
			// standalone activiti, not
			// in spring-context
			elResolver.add(new ReadOnlyMapELResolver(beans));
		}

		elResolver.add(new ArrayELResolver());
		elResolver.add(new ListELResolver());
		elResolver.add(new MapELResolver());
//		elResolver.add(new JsonNodeELResolver());
		elResolver.add(new BeanELResolver());
		return elResolver;
	}

	public Map<Object, Object> getBeans() {
		return beans;
	}

	public void setBeans(Map<Object, Object> beans) {
		this.beans = beans;
	}

	protected ELContext createParsingElContext() {
		return new SimpleContext();
	}

}
